﻿using System;

namespace _033_继承
{
    public class Asset
    {
        public string Name;
    }
    public class Stock : Asset // 从Asset继承
    {
        public long SharesOwned;
    }
    public class House : Asset // 从Asset继承
    {
        public decimal Mortgage;
    }
    class Program
    {
        // 多态，引用是多态的。意味着x类型的变量可以指向x子类的对象。例如：
        public static void Display(Asset asset)
        {
            System.Console.WriteLine(asset.Name);
        }
        static void Main(string[] args)
        {
            Stock msft = new Stock { Name = "MSFT", SharesOwned = 1000 };
            Console.WriteLine(msft.Name); // MSFT
            Console.WriteLine(msft.SharesOwned); // 1000

            House mansion = new House { Name = "Mansion", Mortgage = 250000 };
            Console.WriteLine(mansion.Name);
            Console.WriteLine(mansion.Mortgage);
            // 子类Stock和House都从基类Asset继承了Name属性

            // 这个方法可以用来显示Stock和House类，因为这两个类都继承自Asset类。
            Display(msft);
            Display(mansion);
            // 多态性之所以能实例，是因为子类（Stock和House）具有基类（Asset）的全部特征。

            // 3.2.2 类型转换和引用转换
            // 1.向上类型转换
            // 向上类型转换创建一个基类指向子类的引用。例如：
            Stock msft1 = new Stock();
            Asset a = msft1; // 向上转换
            // 向上转换以后，变量a还是指向msft指向的Stock对象。被引用的对象本身不会被替换或改变：
            Console.WriteLine(a == msft1); // 正确
            // 虽然a和msft指向同一个对象，但a指向对象时有更严格的要求：
            Console.WriteLine(a == msft1); // 正确
            //Console.WriteLine(a.ShareOwned); // 错误：SharesOwned未定义

            // 2.向下类型转换
            Stock msft2 = new Stock();
            Asset a2 = msft2; // 向上转换
            Stock s2 = (Stock)a2; // 向下转换
            Console.WriteLine(s2.SharesOwned); // 没有错误
            Console.WriteLine(s2 == a2); // True
            Console.WriteLine(s2 == msft2); // True

            House h3 = new House();
            Asset a3 = h3; // 向上转换永远会成功
            //Stock s3 = (Stock)a3; // 向下转换出错，a不是Stock类型

            // 3.as运算符
            // as运算符在向下类型转换出错时为变量赋值null（而不是抛出异常）：
            Asset a33 = new Asset();
            Stock s33 = a33 as Stock; // s是null，不抛出异常
            // 这个操作相当有用，接下来只需判断结果是否为null。
            if(s33!=null)
                Console.WriteLine(s33.SharesOwned);
            // 如果不用判断结果是否为null，使用cast更好，因为如果发生错误，cast会抛出描述更清楚的异常。

            // 4.is运算符
            // is运算符用于检查引用的转换能否成功，换句话说，它是检查一个对象是否从某个特定类型派生（或是实现某个接口），经常在向下类型转换前使用。
            if(a33 is Stock)
                Console.WriteLine(((Stock)a).SharesOwned);
            Console.ReadKey();
        }
    }
}
